/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2012-2021. All rights reserved.
 */

package com.huawei.chengdu.meetingdemo.view.dialogs;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Paint.Style;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.huawei.chengdu.meetingdemo.util.LogUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 类名：ExtendTimePicker
 * 描述：时间选择滑轮
 */

public class ExtendTimePicker extends View {
    /**
     * text之间间距和minTextSize之比
     */
    public static final float MARGIN_ALPHA = 4.0f;

    /**
     * 自动回滚到中间的速度
     */
    public static final float SPEED = 2;

    private static final String TAG = "PickerView";

    private static final int SELECT_TEXT_COLOR = 0xFF0A59F7;

    private boolean isScroll = true; // 是否可以循环滚动

    private boolean isDownMove = true; // 是否可以向下滑动

    private boolean isUpMove = true; // 是否可以向上滑动

    private int colorText = 0x333333;

    private int viewHeight;

    private int viewWidth;

    private String startStr = "";

    private String endStr = "";

    private float mMaxTextSize = 20;

    private float mMinTextSize = 20;

    private float maxTextAlpha = 255;

    private float minTextAlpha = 120;

    private float lastDownY;

    /**
     * 滑动的距离
     */
    private float mMoveLen = 0;

    private List<String> dataList;

    private int currentSelected;

    private Paint paint;

    private boolean isInited = false;

    private OnSelectListener selectListener;

    private Timer timer;

    private SendMsgTimerTask task;

    @SuppressLint("HandlerLeak")
    private Handler updateHandler =
            new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    dealMsg();
                }

                private void dealMsg() {
                    if (mMoveLen != 0 && Math.abs(mMoveLen) <= SPEED) {
                        mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED;
                    } else {
                        mMoveLen = 0;
                    }
                    if (task != null) {
                        task.cancel();
                        task = null;
                        performSelect();
                    }
                    invalidate();
                }
            };

    /**
     * 构造函数
     *
     * @param context 上下文
     */
    public ExtendTimePicker(Context context) {
        super(context);
        init();
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrsSet Attribute-Set
     */
    public ExtendTimePicker(Context context, AttributeSet attrsSet) {
        super(context, attrsSet);
        init();
    }

    /**
     * 设置SelectListener
     *
     * @param listener 监听器
     */
    public void setOnSelectListener(OnSelectListener listener) {
        selectListener = listener;
    }

    private void performSelect() {
        if (currentSelected < 0 || currentSelected >= dataList.size()) {
            LogUtil.error(TAG + " select invalid position");
            return;
        }
        if (selectListener != null) {
            selectListener.onSelect(dataList.get(currentSelected));
        }
    }

    /**
     * 设置是否可滑动
     *
     * @param isScroll 是否可滑动
     */
    public void setIsScroll(boolean isScroll) {
        this.isScroll = isScroll;
    }

    /**
     * 设置数据源
     *
     * @param datas 数据源
     */
    public void setData(List<String> datas) {
        if (!isScroll) {
            for (int i = 0; i < 3; i++) {
                datas.add(0, "");
            }
        }
        if (!isScroll) {
            for (int i = 0; i < 3; i++) {
                datas.add("");
            }
            startStr = datas.get(3);
            endStr = datas.get(datas.size() - 4);
            LogUtil.debug(TAG + " startStr:" + startStr);
            LogUtil.debug(TAG + " endStr:" + endStr);
        }
        dataList = datas;
        currentSelected = datas.size() / 2;
        invalidate();
    }

    /**
     * 设置数据源
     *
     * @param datas 数据源
     */
    public void setDataForTry(List<String> datas) {
        dataList = datas;
        currentSelected = datas.size() / 2;
        invalidate();
    }

    /**
     * 设置选择项
     *
     * @param selected 选中项
     */
    public void setSelected(int selected) {
        if (!isScroll) {
            selected = selected + 3;
        }
        currentSelected = selected;
        int distance = dataList.size() / 2 - currentSelected;
        if (distance < 0) {
            for (int i = 0; i < -distance; i++) {
                moveHeadToTail();
                currentSelected--;
            }
        } else if (distance > 0) {
            for (int i = 0; i < distance; i++) {
                moveTailToHead();
                currentSelected++;
            }
        } else {
            moveTailToHead();
        }
        initMoveState();
        invalidate();
    }

    private void moveHeadToTail() {
        String head = dataList.get(0);
        dataList.remove(0);
        dataList.add(head);
    }

    private void moveTailToHead() {
        String tail = dataList.get(dataList.size() - 1);
        dataList.remove(dataList.size() - 1);
        dataList.add(0, tail);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewHeight = getMeasuredHeight();
        viewWidth = getMeasuredWidth();
        // 计算字体大小
        mMaxTextSize = viewHeight / 10.0f;
        mMinTextSize = mMaxTextSize / 2f;
        isInited = true;
        invalidate();
    }

    private void init() {
        timer = new Timer();
        dataList = new ArrayList<>();
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Style.FILL);
        paint.setTextAlign(Align.CENTER);
        paint.setColor(colorText);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (isInited) {
            drawTextData(canvas);
        }
    }

    // 刷新是否可以向上，向下滑动
    private void initMoveState() {
        if (!isScroll) {
            // 判断是否可以向下滑动
            if (currentSelected >= 0 && currentSelected < dataList.size()) {
                isDownMove = !dataList.get(currentSelected).equals(startStr);
                // 判断是否可以向上滑动
                isUpMove = !dataList.get(currentSelected).equals(endStr);
            }
        }
    }

    private void drawTextData(Canvas canvas) {
        initMoveState();
        // 先绘制选中的text再往上往下绘制其余的text
        // 数字4.0用于计算参数，固定字段请勿改动
        float scale = parabola((float) (viewHeight / 4.0), mMoveLen);
        // 数字1.5和48用于计算文字大小，固定参数请勿改动
        float textSize = (float) 1.5 * 48;
        paint.setTextSize(textSize);
        paint.setColor(SELECT_TEXT_COLOR);
        paint.setAlpha((int) ((maxTextAlpha - minTextAlpha) * scale + minTextAlpha));
        // text居中绘制，注意baseLine的计算才能达到居中，y值是text中心坐标
        float xValue = (float) (viewWidth / 2.0);
        float yValue = (float) (viewHeight / 2.0 + mMoveLen);
        FontMetricsInt fmi = paint.getFontMetricsInt();
        float baseLine = (float) (yValue - (fmi.bottom / 2.0 + fmi.top / 2.0));

        // 绘小时or分钟
        canvas.drawText(dataList.get(currentSelected), xValue, baseLine, paint);
        // 绘制上方
        for (int i = 1; (currentSelected - i) >= 0; i++) {
            drawOtherText(canvas, i, -1);
        }
        // 绘制下方
        for (int i = 1; (currentSelected + i) < dataList.size(); i++) {
            drawOtherText(canvas, i, 1);
        }
    }

    /**
     * 绘制其他文字
     *
     * @param canvas 画布
     * @param position 距离mCurrentSelected的差值
     * @param type 1表示向下绘制，-1表示向上绘制
     */
    private void drawOtherText(Canvas canvas, int position, int type) {
        float dValue = MARGIN_ALPHA * mMinTextSize * position + type * mMoveLen;
        // 字体大小不变
        int textSize = 40;
        paint.setTextSize(textSize);
        paint.setColor(colorText);
        // 字体颜色渐淡
        // 数字4.0用于计算参数，固定字段请勿改动
        float scale = parabola((float) (viewHeight / 4.0), dValue);
        paint.setAlpha((int) ((maxTextAlpha - minTextAlpha) * scale + minTextAlpha));
        // 数字2.0用于计算参数，固定字段请勿改动
        float yValue = (float) (viewHeight / 2.0 + type * dValue);
        FontMetricsInt fmi = paint.getFontMetricsInt();
        float baseline = (float) (yValue - (fmi.bottom / 2.0 + fmi.top / 2.0));
        canvas.drawText(dataList.get(currentSelected + type * position), (float) (viewWidth / 2.0), baseline, paint);
    }


    /**
     * 抛物线
     *
     * @param zero zero表示零点坐标
     * @param x x是偏移量
     * @return 返回 scale
     */
    private float parabola(float zero, float x) {
        float fValue = (float) (1 - Math.pow(x / zero, 2));
        return fValue < 0 ? 0 : fValue;
    }

    @Override
    public boolean onTouchEvent(MotionEvent eve) {
        switch (eve.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                doDown(eve);
                break;
            case MotionEvent.ACTION_MOVE:
                doMove(eve);
                break;
            case MotionEvent.ACTION_UP:
                doUp(eve);
                break;
            default:
                break;
        }
        return true;
    }

    private void doDown(MotionEvent eve) {
        if (task != null) {
            task.cancel();
            task = null;
        }
        lastDownY = eve.getY();
    }

    private void doMove(MotionEvent event) {
        mMoveLen += (event.getY() - lastDownY);

        if (mMoveLen > MARGIN_ALPHA * mMinTextSize / 2 && isDownMove) {
            // 往下滑超过离开距离
            moveTailToHead();
            mMoveLen = mMoveLen - MARGIN_ALPHA * mMinTextSize;
        }

        if (mMoveLen < -MARGIN_ALPHA * mMinTextSize / 2 && isUpMove) {
            // 往上滑超过离开距离
            moveHeadToTail();
            mMoveLen = mMoveLen + MARGIN_ALPHA * mMinTextSize;
        }

        lastDownY = event.getY();
        invalidate();
    }

    private void doUp(MotionEvent e) {
        // 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置
        if (Math.abs(mMoveLen) < 0.0001) {
            mMoveLen = 0;
            return;
        }
        if (task != null) {
            task.cancel();
            task = null;
        }
        task = new SendMsgTimerTask(updateHandler);
        timer.schedule(task, 200, 10);
    }

    private class SendMsgTimerTask extends TimerTask {
        Handler updateHandler;

        SendMsgTimerTask(Handler handler) {
            updateHandler = handler;
        }

        @Override
        public void run() {
            updateHandler.sendMessage(updateHandler.obtainMessage());
        }
    }

    /**
     * 选择回调监听
     */
    public interface OnSelectListener {
        /**
         * 选择回调
         *
         * @param text 选中字符串
         */
        void onSelect(String text);
    }
}
